<template>
  <view class="question">
    <!-- 题干（如果是填空题，直接在题干答题） -->
    <view class="question-title">
      <slot name="title-pre"></slot>
      <template v-for="(title, index) in titles" :key="index">
        <text v-if="title.type === 'txt'" class="question-title__text">{{ title.value }}</text>
        <view v-else class="question-title__fill-blank">
          <input
            v-model="userAnswers[title.index]"
            @input="
              () => {
                $emit('update:modelValue', userAnswers)
                $emit('change', userAnswers)
              }
            "
            :disabled="!editable"
            :style="{ width: (title.value.length > 20 ? 20 : title.value.length) * 26 + 50 + 'rpx' }" />
          <text
            :class="{
              'question-title__score': true,
              'question-title__score--err': userScore !== score,
              'question-title__score--succ': userScore === score
            }"></text>
        </view>
      </template>
      <slot name="title-post"></slot>
    </view>
    <!-- 单选题选项 -->
    <view v-if="type === 1">
      <view
        v-for="(option, index) in options"
        :key="index"
        w-full
        box-border
        py-30rpx
        px-20rpx
        bg="#F8F8F8"
        rounded-20rpx
        mb-20rpx
        :class="[
          'question-option',
          { 'is-checked': isChecked(optionLabs(index)) },
          { 'is-succ': isSucc(optionLabs(index)) },
          { 'is-err': isErr(optionLabs(index)) }
        ]"
        @click="
          () => {
            if (!editable) return
            userAnswers[0] = optionLabs(index)
            $emit('update:modelValue', userAnswers)
            $emit('change', userAnswers)
          }
        ">
        {{ optionLabs(index) }}、{{ option }}
      </view>
    </view>
    <!-- 多选题选项
    <checkbox-group
      v-if="type === 2"
      @change="
        (e: any) => {
          userAnswers = e.detail.value
          $emit('update:modelValue', userAnswers)
          $emit('change', userAnswers)
        }
      "
      class="question-option__checkbox-wrap">
      <label
        v-for="(option, index) in options"
        :key="index"
        :class="[
          'question-option',
          { 'is-checked': isChecked(optionLabs(index)) },
          { 'is-succ': isSucc(optionLabs(index)) },
          { 'is-err': isErr(optionLabs(index)) }
        ]">
        <checkbox
          :value="optionLabs(index)"
          :checked="isChecked(optionLabs(index))"
          :disabled="!editable"
          class="question-option__checkbox-hover" />
        <view class="question-option__checkbox">
          <view class="question-option__checkbox-inner"></view>
        </view>
        <text class="question-option__content">{{ optionLabs(index) }}、{{ option }}</text>
      </label>
    </checkbox-group> -->
    <view v-if="type === 2">
      <view
        v-for="(option, index) in options"
        :key="index"
        w-full
        box-border
        py-30rpx
        px-20rpx
        bg="#F8F8F8"
        rounded-20rpx
        mb-20rpx
        :class="[
          'question-option',
          { 'is-checked': isChecked(optionLabs(index)) },
          { 'is-succ': isSucc(optionLabs(index)) },
          { 'is-err': isErr(optionLabs(index)) }
        ]"
        @click="
          () => {
            if (!editable) return
            if (userAnswers.includes(optionLabs(index))) {
              // 如果已选中则取消选择
              userAnswers = userAnswers.filter((v) => v !== optionLabs(index))
            } else {
              // 如果未选中则添加到选中数组
              userAnswers.push(optionLabs(index))
            }
            // 触发事件
            $emit('update:modelValue', userAnswers)
            $emit('change', userAnswers)
            // userAnswers = optionLabs(index)
            // $emit('update:modelValue', userAnswers)
            // $emit('change', userAnswers)
          }
        ">
        {{ optionLabs(index) }}、{{ option }}
      </view>
    </view>
    <!-- 填空题（题干处填空） -->
    <!-- 判断题选项 -->
    <view v-if="type === 4">
      <view
        v-for="(option, index) in judges"
        :key="index"
        w-full
        box-border
        py-30rpx
        px-20rpx
        bg="#F8F8F8"
        rounded-20rpx
        mb-20rpx
        :class="[
          'question-option',
          { 'is-checked': isChecked(optionLabs(index)) },
          { 'is-succ': isSucc(optionLabs(index)) },
          { 'is-err': isErr(optionLabs(index)) }
        ]"
        @click="
          () => {
            if (!editable) return
            userAnswers[0] = option
            $emit('update:modelValue', userAnswers)
            $emit('change', userAnswers)
          }
        ">
        {{ option }}
      </view>
    </view>
    <!-- 问答题答案 -->
    <textarea
      v-if="type === 5"
      v-model="userAnswers[0]"
      @input="
        () => {
          $emit('update:modelValue', userAnswers)
          $emit('change', userAnswers)
        }
      "
      type="textarea"
      placeholder="请输入答案"
      :inputBorder="false"
      :disabled="!editable"
      :styles="{
        backgroundColor: '#F6F7FC'
      }"
      maxlength="999"
      class="question-user-answer"></textarea>
    <!-- 分数 -->
    <view v-if="analysisShow && userScore != 987654" class="question-score">
      <view>
        <text class="question-score__label">得分:</text>
      </view>
      <view>
        <text
          :class="[
            'question-score__user',
            { 'question-score__user--err': userScore === 0 },
            { 'question-score__user--succ': userScore === score }
          ]">
          {{ userScore }}分
        </text>
        <text class="question-score__standard">/{{ score }}分</text>
      </view>
    </view>
    <!-- 答案 -->
    <view v-if="analysisShow && (type === 1 || type === 2 || type === 4)" class="question-select-answer">
      <view class="question-select-answer__diff">
        <text class="question-select-answer__label">作答答案</text>
        <text
          :class="[
            'question-select-answer__value',
            { 'question-select-answer__value--err': userScore === 0 },
            { 'question-select-answer__value--succ': userScore === score }
          ]">
          {{ userAnswers.join('') || '-' }}
        </text>
      </view>
      <view class="question-select-answer__diff">
        <text class="question-select-answer__label">标准答案</text>
        <text class="question-select-answer__value question-select-answer__value--succ">{{ answers.join('') }}</text>
      </view>
    </view>
    <view v-else-if="analysisShow && type === 3" class="question-fill-blank-answer">
      <text class="question-fill-blank-answer__label">标准答案</text>
      <view class="question-title">
        <template v-for="(title, index) in titles" :key="index">
          <text v-if="title.type === 'txt'" class="question-title__text">{{ title.value }}</text>
          <view v-else class="question-title__fill-blank">
            <input
              :value="answers[title.index]"
              :disabled="!editable"
              :style="{ width: (title.value.length > 20 ? 20 : title.value.length) * 26 + 50 + 'rpx' }" />
            <text class="question-title__score"></text>
          </view>
        </template>
      </view>
    </view>
    <view v-else-if="analysisShow && type === 5" class="question-qa-answer">
      <text class="question-qa-answer__label">标准答案</text>
      <view>
        <text class="question-qa-answer__content">{{ answers[0] }}</text>
      </view>
    </view>
    <!-- 解析 -->
    <view v-if="analysisShow && analysis" class="question-analysis">
      <view class="question-analysis__title-wrap">
        <text class="question-analysis__title">解析</text>
      </view>
      <text class="question-analysis__content">{{ analysis || '无' }}</text>
    </view>
  </view>
</template>

<script lang="ts" setup>
import { computed, ref, watch } from 'vue'
import { onLoad } from '@dcloudio/uni-app'

/************************变量定义相关***********************/
const emit = defineEmits<{
  'update:modelValue': string[]
  change: string[]
}>()

const props = withDefaults(
  defineProps<{
    modelValue?: string[] //用户答案
    title: string // 题干
    options?: string[] // 试题选项
    type: number // 试题类型（1：单选；2：多选；3：填空；4：判断；5：问答）
    markType: number // 阅卷方式（1：客观题；2：主观题；
    answers?: string[] // 标准答案
    score: number // 分数
    userScore?: number //用户分数
    analysis?: string // 解析
    editable?: boolean // 可编辑（true：是；false：否）
    answerShow?: boolean // 标准答案显示（true：用户答案显示；false：标准答案显示）
    analysisShow?: boolean // 解析显示（true：显示；false：不显示）
  }>(),
  {
    modelValue: () => [],
    title: '',
    type: 1,
    markType: 1,
    score: 0,
    answers: () => [],
    options: () => [],
    editable: false,
    answerShow: false,
    analysisShow: false
  }
)

watch(
  () => props.analysisShow,
  () => {
    console.log('解析是否显示', props.analysisShow)
  }
)

const judges = ['对', '错'] // 判断题使用
const userAnswers = ref(escape2Html(props.modelValue)) // 用户答案

/************************组件生命周期相关*********************/
onLoad(async () => {
  if (props.type === 3 && !userAnswers.value.length) {
    userAnswers.value = props.title.match(/[_]{5,}/g).map(() => '') // 初始化填空题答案
  }
  if (props.type === 5 && !userAnswers.value.length) {
    userAnswers.value = [''] // 初始化问答题答案
  }
})

/************************计算属性相关*****************************/
const titles = computed(() => {
  // 如果不是填空题，正常返回
  if (props.type !== 3) {
    return [{ type: 'txt', value: props.title, index: -1 }]
  }

  // 如果是填空题，下划线转输入框，用于在题干填空
  let title = props.title // '______AAAAA_____BBBBB____________CCCCC__DDDDD______'
  let titles: any = []
  let pos = 0
  title.match(/[_]{5,}/g)?.forEach((value) => {
    // 大于连续的5个下划线算一个填空
    let index = title.indexOf(value)
    if (index > 0) {
      titles.push({ type: 'txt', value: title.substring(0, index), index: -1 }) // 添加文本
    }
    titles.push({ type: 'input', value, index: pos++ }) //添加输入框；pos用于找对应答案的位置
    title = title.substring(index + value.length) // 解析过的部分题干删除,下次循环从剩余题干中找
  })
  if (title) {
    titles.push({ type: 'txt', value: title, index: -1 }) // 最后一节拼接
  }
  return titles
})

const isChecked = computed(() => (curAnswer: string) => {
  if (!(props.type === 1 || props.type === 2 || props.type === 4)) {
    return false
  }
  return !props.answerShow ? userAnswers.value.includes(curAnswer) : props.answers.includes(curAnswer)
}) // 指定选项是否选中

const isSucc = computed(() => (curAnswer: string) => {
  if (!props.analysisShow) {
    return false
  }

  if (!(props.type === 1 || props.type === 2 || props.type === 4)) {
    return false // 不是单多选判断
  }

  if (!props.answers.includes(curAnswer)) {
    return false
  }

  return true
}) // 指定选项是否答对

const isErr = computed(() => (curAnswer: string) => {
  if (!props.analysisShow) {
    return false
  }

  if (!(props.type === 1 || props.type === 2 || props.type === 4)) {
    return false // 不是单多选判断
  }
  if (userAnswers.value.includes(curAnswer) && !props.answers.includes(curAnswer)) {
    return true
  }
  return false
}) // 指定选项是否答错

const optionLabs = computed(() => (index: number) => {
  if (props.type === 1 || props.type === 2) {
    return String.fromCharCode(65 + index)
  }
  if (props.type === 4) {
    return judges[index]
  }
}) // 获取选项标签

/************************监听相关*****************************/
watch(
  () => props.modelValue,
  () => {
    userAnswers.value = props.modelValue
  }
)

/************************事件相关*****************************/
// 特殊字符转义
function escape2Html(txt: string | string[]) {
  if (typeof txt === 'string') {
    return txt
      .replaceAll('&lt;', '<')
      .replaceAll('&gt;', '>')
      .replaceAll('&amp;', '&')
      .replaceAll('&quot;', '"')
      .replaceAll('&apos;', "'")
      .replaceAll('&ldquo;', '“')
      .replaceAll('&rdquo;', '”')
  }

  if (Array.isArray(txt)) {
    return (txt as string[]).map((t: string) => {
      return t
        .replaceAll('&lt;', '<')
        .replaceAll('&gt;', '>')
        .replaceAll('&amp;', '&')
        .replaceAll('&quot;', '"')
        .replaceAll('&apos;', "'")
        .replaceAll('&ldquo;', '“')
        .replaceAll('&rdquo;', '”')
    })
  }

  return ''
}
</script>

<style lang="scss" scoped>
.question {
  .question-title {
    margin-bottom: 20rpx;
    .question-title__text {
      display: inline;
      font-size: 32rpx;
      color: #000;
      font-weight: 500;
      line-height: 60rpx;
    }
    :deep(.question-title__fill-blank) {
      display: inline-block;
      padding-right: 50rpx;
      border-bottom: 1px solid black;
      position: relative;
      vertical-align: bottom;

      .uni-input-input {
        text-align: center;
      }
      // #ifdef MP-WEIXIN
      input {
        text-align: center;
      }
      // #endif
      .question-title__score {
        position: absolute;
        //left: 50%;
        //dtransform: translateX(-50%);
        right: -10rpx;
        bottom: -5rpx;
        font-size: 24rpx;
        color: #0d9df6;
      }
      .question-title__score--succ {
        color: #18bc38;
      }
      .question-title__score--err {
        color: #e43d33;
      }
    }
  }
  :deep(.question-user-answer) {
    background-color: #f6f7fc;
    width: 100%;
    padding: 20rpx;
    min-height: 600rpx;
    line-height: 50rpx;
    .uni-textarea-wrap {
      min-height: 600rpx;
    }
  }
  .question-score {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 20rpx;
    padding: 0rpx 20rpx;
    height: 96rpx;
    background: #f6f7fc;
    border-radius: 10rpx 10rpx 10rpx 10rpx;
    .question-score__label {
      margin-left: 5rpx;
      font-weight: bold;
      font-size: 34rpx;
      color: #303133;
    }
    .question-score__user {
      font-weight: bold;
      font-size: 34rpx;
      color: #0d9df6;
    }
    .question-score__user--succ {
      color: #18bc38;
    }
    .question-score__user--err {
      color: #e43d33;
    }
    .question-score__standard {
      font-weight: bold;
      font-size: 34rpx;
      color: #999999;
    }
  }
  .question-select-answer {
    display: flex;
    justify-content: center;
    align-items: center;
    margin-top: 20rpx;
    padding: 20rpx 0rpx 10rpx 0rpx;
    background: #f6f7fc;
    border-radius: 10rpx;
    .question-select-answer__diff {
      flex: 1;
      display: flex;
      flex-direction: column;
      align-items: center;
      .question-select-answer__label {
        font-weight: bold;
        font-size: 30rpx;
        color: #999999;
      }
      .question-select-answer__value {
        margin-top: 10rpx;
        font-weight: bold;
        font-size: 30rpx;
        color: #0d9df6;
      }
      .question-select-answer__value--succ {
        color: #18bc38;
      }
      .question-select-answer__value--err {
        color: #e43d33;
      }
    }
  }
  .question-fill-blank-answer {
    margin-top: 20rpx;
    padding: 20rpx;
    background: #f6f7fc;
    border-radius: 10rpx;
    .question-fill-blank-answer__label {
      display: inline-block;
      margin-bottom: 20rpx;
      font-weight: bold;
      font-size: 30rpx;
      color: #999999;
    }
  }
  .question-qa-answer {
    margin-top: 20rpx;
    padding: 20rpx;
    background: #f6f7fc;
    border-radius: 10rpx;
    .question-qa-answer__label {
      margin-top: 20rpx;
      font-weight: bold;
      font-size: 30rpx;
      color: #999999;
    }
    .question-qa-answer__content {
      display: inline-block;
      margin-top: 20rpx;
      line-height: 60rpx;
    }
  }
  .question-analysis {
    margin-top: 30rpx;
    .question-analysis__title-wrap {
      position: relative;
      .question-analysis__title-icon {
        position: absolute;
        left: 0rpx;
        top: 10rpx;
        width: 20rpx;
        height: 20rpx;
        border-radius: 50%;
        background: #2979ff;
      }
      .question-analysis__title-icon1 {
        position: absolute;
        left: 12rpx;
        top: 10rpx;
        width: 20rpx;
        height: 20rpx;
        border-radius: 50%;
        background: #2979ff;
        opacity: 0.6;
      }
      .question-analysis__title {
        font-weight: bold;
        font-size: 36rpx;
        color: #303133;
      }
    }

    .question-analysis__content {
      display: inline-block;
      margin-top: 10rpx;
      line-height: 60rpx;
      font-size: 34rpx;
      color: #303133;
    }
  }
  .question-option__radio-wrap,
  .question-option__checkbox-wrap {
    /* #ifndef APP-NVUE */
    display: flex;
    /* #endif */
    flex-direction: column;
    position: relative;
    margin: 10rpx 0rpx 20rpx 0rpx;
    .question-option {
      /* #ifndef APP-NVUE */
      display: flex;
      /* #endif */
      flex-direction: row;
      align-items: center;

      position: relative;
      margin: 0rpx 0rpx 25rpx 0rpx;
      padding: 20rpx 0rpx 20rpx 20rpx;
      .question-option__radio-hover {
        // 隐藏默认单选按钮
        position: absolute;
        opacity: 0;
      }
      .question-option__checkbox-hover {
        position: absolute;
        opacity: 0;
      }
      .question-option__radio {
        // 重新实现单选按钮
        /* #ifndef APP-NVUE */
        display: flex;
        flex-shrink: 0;
        box-sizing: border-box;
        /* #endif */
        justify-content: center;
        align-items: center;
        position: relative;
        width: 40rpx;
        height: 40rpx;
        border: 2rpx solid #0292f8;
        border-radius: 30rpx;
        background-color: #fff;
        z-index: 1;
        .question-option__radio-inner {
          width: 20rpx;
          height: 20rpx;
          border-radius: 30rpx;
          opacity: 0;
        }
      }
      .question-option__content {
        font-size: 34rpx;
        color: #303133;
        margin: 0rpx 20rpx;
        line-height: 46rpx;
      }
      .question-option__checkbox {
        /* #ifndef APP-NVUE */
        flex-shrink: 0;
        box-sizing: border-box;
        /* #endif */
        position: relative;
        width: 38rpx;
        height: 38rpx;
        border: 2rpx solid #ccc;
        border-radius: 8rpx;
        background-color: #fff;
        z-index: 1;
        .question-option__checkbox-inner {
          position: absolute;
          /* #ifndef APP-NVUE */
          top: 6rpx;
          /* #endif */
          left: 12rpx;
          height: 20rpx;
          width: 14rpx;
          border-right-width: 4rpx;
          border-right-color: #fff;
          border-right-style: solid;
          border-bottom-width: 4rpx;
          border-bottom-color: #fff;
          border-bottom-style: solid;
          opacity: 0;
          transform-origin: center;
          transform: rotate(40deg);
        }
      }
      &.is-checked {
        background-color: #e0f9ff;
        // 选中样式
        .question-option__radio {
          .question-option__radio-inner {
            opacity: 1;
            background: linear-gradient(to right, #04b7f2 0%, #007dfc 100%);
          }
        }
        .question-option__checkbox {
          border-width: 0;
          background: linear-gradient(to right, #04b7f2 0%, #007dfc 100%);

          .question-option__checkbox-inner {
            opacity: 1;
            transform: rotate(45deg);
          }
        }
        .question-option__content {
          font-size: 34rpx;
          color: #303133;
        }
      }
      &.is-succ {
        background-color: #d1f2d7;
        .question-option__radio {
          .question-option__radio-inner {
            opacity: 1;
          }
        }
        .question-option__checkbox {
          .question-option__checkbox-inner {
            opacity: 1;
            transform: rotate(45deg);
          }
        }
        .question-option__content {
        }
      }
      &.is-err {
        background-color: #fad8d6;
        .question-option__radio {
          .question-option__radio-inner {
            opacity: 1;
          }
        }
        .question-option__checkbox {
          .question-option__checkbox-inner {
            opacity: 1;
            transform: rotate(45deg);
          }
        }
        .question-option__content {
        }
      }
    }
  }
}
.is-checked,
.is-succ {
  background-color: #fcc300;
}
.is-err {
  background-color: #ff7654;
}
</style>
